package com.hwd.gmall.payment.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.github.wxpay.sdk.WXPayUtil;
import com.hwd.gmall.common.constant.Const;
import com.hwd.gmall.common.constant.PaymentConst;
import com.hwd.gmall.payment.service.WeiXinPayService;
import com.hwd.gmall.payment.util.HttpClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;

/**
 * 微信支付模块的接口实现类
 *
 * @author 黄伟东/Victor
 * @date 2022/5/10 19:04
 */
@Service
public class WeiXinPayServiceImpl implements WeiXinPayService {

    @Value("${weixin.pay.appid}")
    private String appId;

    @Value("${weixin.pay.partner}")
    private String partner;

    @Value("${weixin.pay.partnerKey}")
    private String partnerKey;

    @Value("${weixin.pay.notifyUrl}")
    private String notifyUrl;

    @Value("${weixin.pay.orderUrl}")
    private String orderUrl;

    @Value("${weixin.pay.checkUrl}")
    private String checkUrl;

    @Value("${weixin.pay.closeUrl}")
    private String closeUrl;

    /**
     * 获取微信支付二维码的接口
     *
     * @param orderMap 参数
     * @return java.util.Map<java.lang.String, java.lang.String>
     */
    @Override
    public Map<String, String> getWeiXinPayUrl(Map<String, String> orderMap) {

        // 参数检验
        if (StringUtils.isEmpty(orderMap.get(PaymentConst.ORDER_ID)) ||
                checkId(orderMap.get(PaymentConst.MONEY)) ||
                StringUtils.isEmpty(orderMap.get(PaymentConst.DESCRIPTION))) {
            throw new RuntimeException("参数错误！");
        }

        try {
            // 获取微信支付二维码地址的HttpClient对象
            HttpClient httpClient = getWeiXinPayUrlHttpClient(orderMap, orderUrl);
            // 返回结果
            return getResultMap(httpClient);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 获取订单的支付结果
     *
     * @param orderId 订单id
     * @return java.util.Map<java.lang.String, java.lang.String>
     */
    @Override
    public Map<String, String> getWeiXinPayResult(String orderId) {

        try {
            // 获取查询微信支付订单结果的接口http客户端对象
            HttpClient httpClient = requestWeiXin(orderId, checkUrl);

            // 返回结果
            return getResultMap(httpClient);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 关闭交易
     *         Map<String, String> resultMap = new HashMap<>(2);
     *         resultMap.put(PaymentConst.RETURN_CODE, Const.SUCCESS);
     *         resultMap.put(PaymentConst.RESULT_CODE, Const.SUCCESS);
     *         return resultMap;
     * @param orderId 订单id
     * @return java.util.Map<java.lang.String, java.lang.String>
     */
    @Override
    public Map<String, String> closePay(String orderId) {

        try {
            // 发起关闭下单
            HttpClient httpClient = requestWeiXin(orderId, closeUrl);
            // 返回结果
            return getResultMap(httpClient);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 调用微信支付接口
     *
     * @param orderId 订单id
     * @param url     查询微信支付订单的接口url
     * @return com.hwd.gmall.payment.util.HttpClient
     */
    private HttpClient requestWeiXin(String orderId, String url) throws Exception {

        // 参数检验
        if (StringUtils.isEmpty(orderId)) {
            throw new RuntimeException("参数错误！");
        }

        // 创建远程调用微信服务httpClient
        HttpClient httpClient = new HttpClient(url);
        httpClient.setHttps(true);

        // 设置请求参数，要求的是xml格式的内容
        Map<String, String> params = putBaseParams(orderId);

        // 将map参数转换为xml，同时生成签名
        String xmlParam = WXPayUtil.generateSignedXml(params, partnerKey);
        // 设置参数
        httpClient.setXmlParam(xmlParam);

        // 发起调用
        httpClient.post();

        return httpClient;
    }

    /**
     * 设置调用微信支付接口的基本参数
     *
     * @param orderId 订单id
     * @return java.util.Map<java.lang.String, java.lang.String>
     */
    private Map<String, String> putBaseParams(String orderId) {
        Map<String, String> params = new HashMap<>(16);
        params.put("appid", appId);
        params.put("mch_id", partner);
        params.put("nonce_str", WXPayUtil.generateNonceStr());
        params.put("out_trade_no", orderId);
        return params;
    }

    /**
     * 获取调用微信支付接口的返回结果
     *
     * @param httpClient httpClient对象
     * @return java.util.Map<java.lang.String, java.lang.String>
     */
    private Map<String, String> getResultMap(HttpClient httpClient) {
        try {
            // 获取返回结果(XML格式的字符串)，把XML格式的字符串转化为map
            Map<String, String> resultMap = WXPayUtil.xmlToMap(httpClient.getContent());
            // 获取支付的二维码地址
            if (Const.SUCCESS.equals(resultMap.get(PaymentConst.RETURN_CODE)) &&
                    Const.SUCCESS.equals(resultMap.get(PaymentConst.RESULT_CODE))) {
                // 返回结果
                return resultMap;
            } else {
                throw new RuntimeException("请求错误!!!");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 设置获取微信支付二维码地址的HttpClient对象
     *
     * @param orderMap 参数
     * @param url      微信支付接口url
     * @return com.hwd.gmall.payment.util.HttpClient
     */
    private HttpClient getWeiXinPayUrlHttpClient(Map<String, String> orderMap, String url) throws Exception {
        // 创建远程调用微信服务httpClient
        HttpClient httpClient = new HttpClient(url);
        httpClient.setHttps(true);

        // 设置请求参数，要求的是xml格式的内容
        Map<String, String> params = putBaseParams(orderMap.get(PaymentConst.ORDER_ID));

        params.put("body", orderMap.get(PaymentConst.DESCRIPTION));
        params.put("total_fee", orderMap.get(PaymentConst.MONEY));
        params.put("spbill_create_ip", "192.168.200.1");
        params.put("notify_url", notifyUrl);
        params.put("trade_type", "NATIVE");

        // 附加参数
        Map<String, String> attachMap = new HashMap<>(2);
        attachMap.put("exchange", orderMap.get("exchange"));
        attachMap.put("routingKey", orderMap.get("routingKey"));
        //保存附加参数
        params.put("attach", JSONObject.toJSONString(attachMap));

        // 将map参数转换为xml，同时生成签名
        String xmlParam = WXPayUtil.generateSignedXml(params, partnerKey);
        // 设置参数
        httpClient.setXmlParam(xmlParam);

        // 发起调用
        httpClient.post();

        return httpClient;
    }

    /**
     * 检验参数是否为金额：大于零，整数
     *
     * @param money 金额
     * @return boolean true:参数错误
     */
    private boolean checkId(String money) {
        try {
            if (StringUtils.isEmpty(money) || Long.parseLong(money) < 0) {
                return true;
            }
        } catch (Exception e) {
            return false;
        }
        return false;
    }
}
